package bg.uni_sofia.conf_manager.beans;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MultivaluedMap;

import bg.uni_sofia.conf_manager.model.Conference;
import bg.uni_sofia.conf_manager.model.Lecturer;

@Stateless
@Path("/lecturer")
public class LecturerBean {
	@PersistenceContext
	private EntityManager em;
	@Inject
	LoginBean sesData;

	public LecturerBean() {

	}

	@POST
	@Consumes("application/json")
	public String addLecturer(Lecturer newLecturer)
			throws NoSuchAlgorithmException {
		String username = newLecturer.getUsername();
		String password = newLecturer.getPassword();
		Pattern patternUsername = Pattern.compile("/^[A-z][A-z0-9]*$/");
		Matcher matcherUsername = patternUsername.matcher(username);
		Pattern patternPassword = Pattern
				.compile("/(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z])/");
		Matcher matcherPass = patternPassword.matcher(password);

		TypedQuery<Long> queryByName = em.createNamedQuery(
				"checkExistLecturerName", Long.class);
		queryByName.setParameter("username", username);
		TypedQuery<Long> queryByMail = em.createNamedQuery(
				"checkExistLecturerMail", Long.class);
		queryByMail.setParameter("email", newLecturer.getEmail());

		if (!queryByName.getSingleResult().equals(0l)) {
			return "Choose another name!";
		} else if (!queryByMail.getSingleResult().equals(0l)) {
			return "Enter another email address!";
		} else {
			newLecturer.setPassword(hashPassword(password));
			newLecturer.setLastLogin(new Date());
			em.persist(newLecturer);
			return "Registration successful!";
		}

	}

	@POST
	@Path("/changePassword")
	@Consumes("application/json")
	public boolean changePassword(String newPassword) {
		TypedQuery<Lecturer> query = em.createNamedQuery(
				"changePasswordByLecturerName", Lecturer.class);
		try {
			String username = sesData.getUsername();
			query.setParameter("username", username);
			query.setParameter("password", hashPassword(newPassword));
			query.executeUpdate();
			return true;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return false;
	}

	@GET
	@Path("/getFavoriteConferences")
	@Consumes("application/json")
	public List<Conference> getFavoriteConferences() {
		TypedQuery<Lecturer> query = em.createNamedQuery("getLecturerById",
				Lecturer.class);
		long lecturerID = sesData.getId();
		System.out.println("Lecture ID " + lecturerID);
		query.setParameter("id", lecturerID);

		if (query.getResultList().size() > 0) {
			Lecturer lec = query.getResultList().get(0);
			System.out.println(lec);
			return lec.getConferences();
		} else {
			return null;
		}
	}

	@GET
	@Path("/{conferenceName}")
	@Produces("application/json")
	public boolean isFavoriteConference(
			@PathParam("conferenceName") String conferenceName) {
		List<Conference> favoriteConferences = getFavoriteConferences();
		TypedQuery<Conference> query = em.createNamedQuery(
				"getConferenceByName", Conference.class);
		query.setParameter("name", conferenceName);
		List<Conference> conf = query.getResultList();
		Conference conference = conf.get(0);
		if (favoriteConferences.contains(conference)) {
			System.out.println("is favorite");
			return true;
		} else {
			System.out.println("is not favorite");
			return false;
		}

	}

	@POST
	@Path("/changeEmail")
	@Consumes("application/json")
	public boolean changeEmail(String newEmail) {
		TypedQuery<Lecturer> query = em.createNamedQuery(
				"changeEmailByLecturerName", Lecturer.class);
		String username = sesData.getUsername();
		query.setParameter("username", username);
		query.setParameter("email", newEmail);
		query.executeUpdate();
		return true;
	}

	@POST
	@Path("/updatePrivilege")
	@Consumes("application/json")
	public boolean updatePrivileges(boolean isActive) {
		TypedQuery<Lecturer> query = em.createNamedQuery(
				"updateLecturerPrivilege", Lecturer.class);
		String username = sesData.getUsername();
		query.setParameter("username", username);
		query.setParameter("isActive", isActive);
		try {
			query.executeUpdate();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	@POST
	@Path("/addConference/{conferenceName}")
	@Consumes("application/json")
	public Conference addConference(
			@PathParam("conferenceName") String conferenceName) {
		TypedQuery<Conference> queryByName = em.createNamedQuery(
				"getConferenceByName", Conference.class);
		queryByName.setParameter("name", conferenceName);
		Conference conference = queryByName.getResultList().get(0);

		long lecturerID = sesData.getId();
		TypedQuery<Lecturer> queryLecturer = em.createNamedQuery(
				"getLecturerById", Lecturer.class);
		queryLecturer.setParameter("id", lecturerID);
		List<Lecturer> lecturersList = queryLecturer.getResultList();

		Lecturer lecturer = null;
		if (lecturersList.size() > 0) {
			lecturer = lecturersList.get(0);
		}

		lecturer.addConference(conference);
		em.merge(lecturer);
		return conference;
	}

	public static String hashPassword(String password)
			throws NoSuchAlgorithmException {

		MessageDigest md = MessageDigest.getInstance("SHA-1");
		md.update(password.getBytes());
		byte byteData[] = md.digest();
		return new String(bytesToHex(byteData));

	}

	public static String bytesToHex(byte[] b) {
		char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
				'A', 'B', 'C', 'D', 'E', 'F' };
		StringBuffer buf = new StringBuffer();
		for (int j = 0; j < b.length; j++) {
			buf.append(hexDigit[(b[j] >> 4) & 0x0f]);
			buf.append(hexDigit[b[j] & 0x0f]);
		}
		return buf.toString();
	}
	
	 @POST
     @Path("/changeEmailMobile")
     @Consumes("application/x-www-form-urlencoded")
     public boolean changeEmail(MultivaluedMap<String, String> data) {
             TypedQuery<Lecturer> query = em.createNamedQuery(
                             "changeEmailByLecturerName", Lecturer.class);
             query.setParameter("username", data.get("username").get(0));
             query.setParameter("email", data.get("email").get(0));
             query.executeUpdate();
             return true;
     }

     @POST
     @Path("/deactivateMobile")
     @Consumes("application/x-www-form-urlencoded")
     public boolean updatePrivilegesMobile(MultivaluedMap<String, String> data) {
             TypedQuery<Lecturer> query = em.createNamedQuery(
                             "updateLecturerPrivilege", Lecturer.class);
             query.setParameter("username", data.get("username").get(0));
             query.setParameter("isActive", false);
             try {
                     query.executeUpdate();
                     return true;
             } catch (Exception e) {
                     e.printStackTrace();
             }
             return false;
     }

     @POST
     @Path("/changePasswordMobile")
     @Consumes("application/x-www-form-urlencoded")
     public boolean changePasswordMobile(MultivaluedMap<String, String> data) {
             TypedQuery<Lecturer> query = em.createNamedQuery(
                             "changePasswordByLecturerName", Lecturer.class);
             try {
                     query.setParameter("username", data.get("username").get(0));
                     query.setParameter("password", hashPassword(data.get("password")
                                     .get(0)));
                     query.executeUpdate();
                     return true;
             } catch (NoSuchAlgorithmException e) {
                     e.printStackTrace();
             }
             return false;
     }
	
}
